import re
from pony import orm

from ..models.db import DingDianHospital, HospitalNickname, ProvinceCity, Area, MedicineNormalize, \
    ChineseMedicineNormalize, MedicalInsuranceCatalogue, MedicalServiceNormalize,ConsumableNormalize, Component
from .cosine_similary import pre_processing
from .medical_service_normalization import MedicalServiceNormalization
from .medicine_normalization import MedicineNormalizaiton
from .medical_consumables_normalization import ConsumablesNormalization


class CostDetailslNorm:
    def __int__(self):
        self.medicine_normalization_func = MedicineNormalizaiton()
        self.medical_service_normalization_func = MedicalServiceNormalization()
        self.medical_consumable_normalization_func = ConsumablesNormalization()

    # 统一为英文符号
    def ch_en(self, word):
        # 统一为英文符号
        intab = u"！—。【】“”‘’《》—「」『』〖〗〔〕〓︰﹒﹕﹙﹚﹝﹞﹢〈〉∽∶‥–‒Ι×[]（）＃［］{}：％＊﹛﹜，－／÷＿﹡；ⅹ"
        outab = u"!-.()\"\"\'\'()-()()()()=:.:()()+()~::--i*()()#()():%*(),-//_*;*"
        trantab = str.maketrans(intab, outab)  # 一一映射。
        word = word.translate(trantab)  # 返回字符串S的副本，其中每个字符都已通过给定的转换表进行映射。
        if re.findall("＜.*?＞", word):
            word = word.replace("＜", "(")
            word = word.replace("＞", ")")
        if re.findall("<.*?>", word):
            word = word.replace("<", "(")
            word = word.replace(">", ")")
        return word

    def classification_by_component(self, word):
        '''
        查询输入词条中包含哪些特定的部件
        '''
        candidate_component_dict = {'剂型':[],
                                    '药品特有词汇':[],
                                    '医保药品': [],
                                    '医疗服务特有词汇':[],
                                    '耗材特有词汇':[]}
        with orm.db_session:
            candidate_component_list = list(orm.distinct(
                (component.name,
                 component.type)
                for component in Component
                if
                component.name in word
            ))
            for data in candidate_component_list:
                if data[1] in candidate_component_dict.keys():
                    candidate_component_dict[data[1]].append(data[0])

            # 统计输入词条中是否包含药品通用名和药品特有词汇
            medicine_component_count = len(candidate_component_dict['药品特有词汇'])
            insurance_medicine_count = len(candidate_component_dict['医保药品'])
            # TODO 机型能否作为一个判定项，待定
            dosage_form_list = len(candidate_component_dict['剂型'])
            medicine_component_sign = int(medicine_component_count + insurance_medicine_count!=0)

            # 统计输入词条中是否包含医疗服务特有词汇且该词条以该特有词汇结尾
            medical_service_component_sign = 0
            for data in candidate_component_dict['医疗服务特有词汇']:
                if word.endswith(data):
                    medical_service_component_sign = 1
                    break

            # 统计输入词条中是否包含耗材特有词汇
            consumable_component_sign = int(len(candidate_component_dict['耗材特有词汇']) !=0)

            # 如果词条以医疗服务特定词结尾，则一定是医疗服务
            if medical_service_component_sign:
                return '医疗服务'
            # 如果在不同类中出现了标志，暂时无法判断是哪种类型
            elif medicine_component_sign + medical_service_component_sign + consumable_component_sign > 0:
                return '未知'
            elif medicine_component_sign:
                return '药品'
            elif consumable_component_sign:
                return '耗材'
            else:
                return '未知'

    def search_city_by_hospital(self, input_hospital):
        """
        查询输入的医院是否包含某地地名
        :param input_hospital: 输入医院。
        :return: 地名。
        """
        with orm.db_session:
            candidate_city_list = list(orm.distinct(
                city.city_name
                for city in ProvinceCity
                if
                city.city_name in input_hospital
            ))

            if candidate_city_list == []:
                fuzzy_city_list = list(orm.select(
                    city.city_name
                    for city in ProvinceCity
                ).order_by(orm.raw_sql('SIMILARITY(city.city_name, $input_hospital) DESC')).limit(5))
                candidate_city_list=[data for data in fuzzy_city_list if data.replace('市', '') in input_hospital]

            return candidate_city_list

    def medicine_synonym_match(self, enter):
        """
        精准匹配:药品同义词库。
        :param enter: 输入字符串
        :return: 精准匹配结果
        """
        with orm.db_session:
            candidate_medicine_list = list(orm.select(
                medicine.nhsa_name
                for medicine in MedicineNormalize
                if
                medicine.other_name == enter
            ))

            return candidate_medicine_list

    def chinese_medicine_synonym_match(self, enter):
        """
        精准匹配:中药的药品同义词库。
        :param enter: 输入字符串
        :return: 精准匹配结果
        """
        with orm.db_session:
            candidate_medicine_list = list(orm.select(
                medicine.name
                for medicine in ChineseMedicineNormalize
                if
                medicine.other_name == enter
            ))

            return candidate_medicine_list

    def consumable_synonym_match(self, enter):
        """
        精准匹配:医疗服务同义词库。
        :param enter: 输入字符串
        :return: 精准匹配结果
        """
        with orm.db_session:
            candidate_medicine_list = list(orm.select(
                medical_service.fourth_level_name
                for medical_service in ConsumableNormalize
                if
                medical_service.other_name == enter
            ))

            return candidate_medicine_list

    def medical_insurance_catalogue_search(self, input_cost_detail, input_city, input_medical_insurance_type):
        """
        医保三目录查询
        :param input_hospital: 输入医院。
        :return: 地名。
        """
        with orm.db_session:
            candidate_medical_insurance_catalogue_list = list(orm.select(
                (cost_detail.name,
                 cost_detail.medical_insurance_type,
                 cost_detail.self_pay_proportion_worker,
                 cost_detail.self_pay_proportion_resident,
                 cost_detail.self_pay_proportion_student,
                 cost_detail.self_pay_proportion_industrial_injury,
                 cost_detail.self_pay_proportion_maternity)
                for cost_detail in MedicalInsuranceCatalogue
                if
                cost_detail.name == input_cost_detail
                and
                cost_detail.city == input_city
            ))
            # TODO 理论上应该只能查出来一个，为避免数据库有误，查出来多个，先暂时返回第一个
            if candidate_medical_insurance_catalogue_list:
                out_put = [{'name': data[0],
                                 'medical_insurance_type': data[1],
                                 'self_pay_proportion_worker': data[2],
                                 'self_pay_proportion_resident': data[3],
                                 'self_pay_proportion_student': data[4],
                                 'self_pay_proportion_industrial_injury': data[5],
                                 'self_pay_proportion_maternity': data[6],
                                 } for data in candidate_medical_insurance_catalogue_list][0]
            else:
                # TODO 如果没查到，暂时返回空
                out_put = {'name': input_cost_detail,
                                 'medical_insurance_type': '',
                                 'self_pay_proportion_worker': '',
                                 'self_pay_proportion_resident': '',
                                 'self_pay_proportion_student': '',
                                 'self_pay_proportion_industrial_injury': '',
                                 'self_pay_proportion_maternity': '',
                                 }
            return out_put

    def normalized(self, input_list: str, hospital: str, insurance_type: str):
        """
         归一化入口
        """
        medical_insurance_catalogue_list = []

        # 根据医院确定省市地区
        # 医院名称中如果包含某个地级市的全称，暂定为该医院就是这个城市的
        candidate_city = ''
        candidate_city_list = self.search_city_by_hospital(hospital)
        if len(candidate_city_list) > 0:
            candidate_city = candidate_city_list[0]
        # 如果找不到城市，则使用医院归一化来确定城市

        for data in input_list:
            name = data[0]
            prossed_name = data[1]
            if name.strip() == '' and prossed_name == '':
                medical_insurance_catalogue_list.append([])
            # 药品同义词精准匹配\中药同义词精准匹配
            normalized_result_list = self.medicine_normalization_func.medicine_accurate_match(name,prossed_name)
            # 如果精准匹配到了药品
            if not normalized_result_list[0] == []:
                for normalized_result in normalized_result_list[0]:
                    medical_insurance_catalogue_search_result = self.medical_insurance_catalogue_search(
                        normalized_result, candidate_city, '')
                    medical_insurance_catalogue_list.append(medical_insurance_catalogue_search_result[0])
                    continue

            # 医疗服务同义词精准匹配
            normalized_result_list = self.medical_service_normalization_func.medicine_accurate_match(name, prossed_name)
        normalized_result_list = self.medical_service_synonym_match(enter=name)
        if len(normalized_result_list) > 0:
            # 扣费比例查询，理论上只能查出来一条
            for normalized_result in normalized_result_list:
                medical_insurance_catalogue_search_result = self.medical_insurance_catalogue_search(normalized_result,candidate_city, '')
                medical_insurance_catalogue_list.append(medical_insurance_catalogue_search_result)
            return medical_insurance_catalogue_list

        # 耗材同义词精准匹配
        normalized_result_list = self.consumable_synonym_match(enter=name)
        if len(normalized_result_list) > 0:
            # 扣费比例查询，理论上只能查出来一条
            for normalized_result in normalized_result_list:
                medical_insurance_catalogue_search_result = self.medical_insurance_catalogue_search(normalized_result,candidate_city, '')
                medical_insurance_catalogue_list.append(medical_insurance_catalogue_search_result)
            return medical_insurance_catalogue_list

        # 在大库中查找该词条是否有大项，通过大项进行分类

        # 对输入词条进行分类
        classification_result = self.classification_by_component(name)
        if classification_result == '药品':
            pass
        elif classification_result == '医疗服务':
            pass
        elif classification_result =='耗材':
            pass
        # 分类失败,每种类型里面都进行推荐
        else:
            pass